#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
信号格式化工具 - 统一所有交易信号的显示格式

职责：
1. 统一信号原因显示格式
2. 标准化条件标签（A/B/C/D）
3. 技术形态强度可视化（星级显示）
4. 提供简洁易读的日志输出

使用示例：
    from utils.signal_formatter import format_signal, SignalType
    
    # 格式化卖出信号
    formatted = format_signal(signal, SignalType.SELL)
    print(formatted)  # 输出: 【C+技术】长线卖出: 盈利5.2% | 上影线确认 [★★★☆☆]
"""

from typing import Dict, Optional
from enum import Enum

class SignalType(Enum):
    """信号类型枚举"""
    BUY = "buy"
    SELL = "sell"

class ConditionType(Enum):
    """条件类型枚举"""
    # 策略条件
    EMERGENCY_STOP = "A"          # 紧急止损
    SHORT_TERM_SELL = "B"         # 短线卖出
    LONG_TERM_SELL = "C"          # 长线卖出
    
    # 技术形态条件
    TECH_ENHANCED = "C+技术"      # 策略+技术增强
    TECH_INDEPENDENT = "D-技术"   # 技术独立触发
    
    # 买入条件
    BREAKOUT_BUY = "买入"         # 突破买入

class SignalFormatter:
    """信号格式化器"""
    
    # 条件类型标签映射
    CONDITION_LABELS = {
        'emergency_stop': '【A-止损】',
        'short_term_sell': '【B-短线】',
        'long_term_sell': '【C-长线】',
        'tech_enhanced': '【C+技术】',
        'tech_independent': '【D-技术】',
        'strategy_buy': '【买入】',
    }
    
    # 技术形态名称映射（中文显示）
    PATTERN_NAMES = {
        'upper_shadow': '上影线',
        'doji': '十字星',
        'hammer': '锤子线',
    }
    
    @classmethod
    def format_signal(cls, signal: Dict, signal_type: SignalType = SignalType.SELL) -> str:
        """
        格式化信号为易读的字符串
        
        Args:
            signal: 信号字典，包含 reason, tech_strength, pattern 等字段
            signal_type: 信号类型（买入/卖出）
        
        Returns:
            格式化后的字符串
        
        示例输出：
            【C+技术】长线卖出: 盈利5.2% | 上影线确认 [★★★☆☆]
            【D-技术】独立卖出: 上影线强烈信号 [★★★★★]
            【A-止损】紧急止损: 跌破5日线2.8%
        """
        # 提取信号信息
        reason = signal.get('reason', '未知原因')
        condition_type = signal.get('condition_type', 'unknown')
        tech_strength = signal.get('tech_strength')
        pattern = signal.get('pattern')
        
        # 获取条件标签
        label = cls.CONDITION_LABELS.get(condition_type, '【未知】')
        
        # 构建基础信息
        formatted = f"{label} {reason}"
        
        # 添加技术形态信息
        if tech_strength is not None:
            # 星级显示（1-5星）
            stars = cls._format_strength_stars(tech_strength)
            
            # 技术形态名称
            if pattern:
                pattern_name = cls.PATTERN_NAMES.get(pattern, pattern)
                formatted = f"{formatted} [{stars}]"
            else:
                formatted = f"{formatted} [强度: {stars}]"
        
        return formatted
    
    @classmethod
    def _format_strength_stars(cls, strength: float) -> str:
        """
        将技术强度转换为星级显示
        
        Args:
            strength: 强度值（0-5分）
        
        Returns:
            星级字符串，如 "★★★☆☆"
        """
        full_stars = min(5, int(strength))
        empty_stars = 5 - full_stars
        return '★' * full_stars + '☆' * empty_stars
    
    @classmethod
    def format_tech_pattern(cls, pattern: str, strength: float) -> str:
        """
        格式化技术形态信息
        
        Args:
            pattern: 形态类型（upper_shadow/doji/hammer）
            strength: 强度值（0-5）
        
        Returns:
            格式化字符串，如 "上影线(★★★☆☆)"
        """
        pattern_name = cls.PATTERN_NAMES.get(pattern, pattern)
        stars = cls._format_strength_stars(strength)
        return f"{pattern_name}({stars})"
    
    @classmethod
    def extract_condition_type(cls, signal: Dict) -> str:
        """
        从信号中提取条件类型
        
        Args:
            signal: 信号字典
        
        Returns:
            条件类型字符串（A/B/C/C+技术/D-技术）
        """
        # 如果已有 condition_type，直接返回
        if 'condition_type' in signal:
            condition_type = signal['condition_type']
            type_map = {
                'emergency_stop': 'A',
                'short_term_sell': 'B',
                'long_term_sell': 'C',
                'tech_enhanced': 'C+技术',
                'tech_independent': 'D-技术',
            }
            return type_map.get(condition_type, condition_type)
        
        # 根据 source 字段判断
        source = signal.get('source', '')
        if source == 'technical_independent':
            return 'D-技术'
        elif 'tech_strength' in signal:
            return 'C+技术'
        
        # 根据 reason 关键字判断
        reason = signal.get('reason', '')
        if '止损' in reason or '【条件A】' in reason:
            return 'A'
        elif '短线' in reason or '【条件B】' in reason:
            return 'B'
        elif '长线' in reason or '【条件C】' in reason:
            return 'C'
        elif '【条件D】' in reason or '技术形态独立' in reason:
            return 'D-技术'
        
        return '未知'
    
    @classmethod
    def format_compact(cls, signal: Dict) -> str:
        """
        紧凑格式输出（用于日志）
        
        Args:
            signal: 信号字典
        
        Returns:
            紧凑格式字符串，如 "[C+技术★★★] 长线卖出"
        """
        condition = cls.extract_condition_type(signal)
        reason = signal.get('reason', '').split(':')[-1].strip()  # 只取原因部分
        
        # 如果有技术强度，添加星级
        if 'tech_strength' in signal:
            stars = '★' * min(5, int(signal['tech_strength']))
            return f"[{condition}{stars}] {reason}"
        else:
            return f"[{condition}] {reason}"
    
    @classmethod
    def format_detailed(cls, signal: Dict, include_metrics: bool = True) -> str:
        """
        详细格式输出（用于回测报告）
        
        Args:
            signal: 信号字典
            include_metrics: 是否包含详细指标
        
        Returns:
            详细格式字符串
        """
        formatted = cls.format_signal(signal)
        
        if not include_metrics:
            return formatted
        
        # 添加详细指标
        details = []
        
        if 'tech_enhancement' in signal:
            enhancement = signal['tech_enhancement']
            details.append(f"增强系数: {enhancement:.1%}")
        
        if 'sell_ratio' in signal:
            ratio = signal['sell_ratio']
            details.append(f"卖出比例: {ratio:.0%}")
        
        if 'price' in signal:
            price = signal['price']
            details.append(f"价格: {price:.2f}")
        
        if details:
            formatted += f" | {' | '.join(details)}"
        
        return formatted

# ============================================================================
# 便捷函数（简化接口）
# ============================================================================

def format_signal(signal: Dict, signal_type: SignalType = SignalType.SELL) -> str:
    """
    快速格式化信号（便捷函数）
    
    示例：
        formatted = format_signal(signal)
        print(formatted)
    """
    return SignalFormatter.format_signal(signal, signal_type)

def format_compact(signal: Dict) -> str:
    """快速紧凑格式化"""
    return SignalFormatter.format_compact(signal)

def format_detailed(signal: Dict, include_metrics: bool = True) -> str:
    """快速详细格式化"""
    return SignalFormatter.format_detailed(signal, include_metrics)

def extract_condition_type(signal: Dict) -> str:
    """快速提取条件类型"""
    return SignalFormatter.extract_condition_type(signal)

# ============================================================================
# 交易输出格式化工具（用于回测/实盘/模拟盘的完整交易输出）
# ============================================================================

class TradeFormatter:
    """交易输出格式化器 - 统一买入/卖出交易的完整输出格式"""
    
    @staticmethod
    def format_buy_output(
        stock_name: str,
        trade_time: str,
        price: float,
        actual_price: float,
        slippage_rate: float,
        shares: int,
        amount: float,
        commission: float,
        total_cost: float,
        remaining_capital: float,
        reason: str,
        planned_ratio: Optional[float] = None,
        actual_ratio: Optional[float] = None
    ) -> list:
        """
        格式化买入交易的完整输出
        
        Returns:
            list: 输出行列表，可以直接用 logger.info() 逐行输出
        """
        lines = []
        
        # 获取显示名称
        display_name = stock_name
        
        # 分隔线
        lines.append("━" * 50)
        
        # 买入标题
        lines.append(f"🔴 【买入】{display_name} | {trade_time}")
        
        # 价格行
        slippage_arrow = "↑" if slippage_rate > 0 else "↓"
        price_info = f"💲 价格: {price:.2f}→{actual_price:.2f}元({slippage_arrow}{slippage_rate*100:.2f}%滑点)"
        
        # 数量/仓位行
        if planned_ratio is not None:
            quantity_info = f"📊 数量: {shares}股(计划{planned_ratio:.2f}%→实际{actual_ratio:.2f}%)"
        else:
            quantity_info = f"📊 数量: {shares}股(实际{actual_ratio:.2f}%)"
        
        lines.append(f"{price_info} | {quantity_info}")
        
        # 资金行（如果剩余资金为0，则不显示）
        if remaining_capital > 0:
            lines.append(f"💰 金额: {amount:,.2f}元 + 手续费{commission:.2f}元 = {total_cost:,.2f}元 | 剩余: {remaining_capital:,.2f}元")
        else:
            lines.append(f"💰 金额: {amount:,.2f}元 + 手续费{commission:.2f}元 = {total_cost:,.2f}元")
        
        # 原因行
        lines.append(f"📝 原因: {reason}")
        
        # 分隔线
        lines.append("━" * 50)
        
        return lines
    
    @staticmethod
    def format_sell_output(
        stock_name: str,
        trade_time: str,
        price: float,
        actual_price: float,
        slippage_rate: float,
        shares: int,
        sell_amount: float,
        commission: float,
        remaining_capital: float,
        reason: str,
        is_full_sell: bool = True,
        planned_sell_ratio: Optional[float] = None,
        actual_sell_ratio: Optional[float] = None,
        remaining_shares: int = 0,
        buy_price: float = 0,
        profit: float = 0,
        profit_rate: float = 0,
        hold_days: int = 0,
        trigger_count: Optional[int] = None
    ) -> list:
        """
        格式化卖出交易的完整输出
        
        Returns:
            list: 输出行列表，可以直接用 logger.info() 逐行输出
        """
        lines = []
        
        # 获取显示名称
        display_name = stock_name
        
        # 分隔线
        lines.append("━" * 50)
        
        # 卖出标题
        sell_type = "全部" if is_full_sell else "部分"
        lines.append(f"🟢 【卖出】{display_name} {sell_type} | {trade_time}")
        
        # 价格行
        slippage_arrow = "↑" if slippage_rate > 0 else "↓"
        price_info = f"💲 价格: {price:.2f}→{actual_price:.2f}元({slippage_arrow} {slippage_rate*100:.2f}%滑点)"
        
        # 数量/仓位行
        if planned_sell_ratio is not None:
            if abs(actual_sell_ratio - planned_sell_ratio) > 1:  # 差异>1%才显示对比
                quantity_info = f"📊 数量: {shares}股(计划减仓{planned_sell_ratio:.0f}%→实际{actual_sell_ratio:.1f}%)"
            else:
                quantity_info = f"📊 数量: {shares}股(减仓{actual_sell_ratio:.1f}%)"
        else:
            quantity_info = f"📊 数量: {shares}股(减仓{actual_sell_ratio:.1f}%)"
        
        if not is_full_sell:
            quantity_info += f" 剩余{remaining_shares}股"
        
        lines.append(f"{price_info} | {quantity_info}")
        
        # 分批减仓提示行（如果是条件A触发）
        if trigger_count is not None:
            sell_actions = {
                1: "减仓30%",
                2: "再减仓40%",
                3: "清仓剩余30%",
                4: "清仓剩余30%",
                5: "清仓剩余30%"
            }
            action_desc = sell_actions.get(trigger_count, f"减仓{planned_sell_ratio:.0f}%")
            lines.append(f"📊 分批减仓: 第{trigger_count}次触发 → {action_desc}")
        
        # 资金行（如果剩余资金为0，则不显示）
        if remaining_capital > 0:
            lines.append(f"💰 金额: {sell_amount:,.2f}元 - 手续费{commission:.2f}元 = {sell_amount - commission:,.2f}元 | 余额: {remaining_capital:,.2f}元")
        else:
            lines.append(f"💰 金额: {sell_amount:,.2f}元 - 手续费{commission:.2f}元 = {sell_amount - commission:,.2f}元")
        
        # 盈亏行（明确标注买入价和卖出价）
        if buy_price > 0:
            profit_emoji = "📈" if profit > 0 else "📉"
            lines.append(f"{profit_emoji} 盈亏: {buy_price:.2f}(买)→{actual_price:.2f}(卖) | {profit:+,.2f}元({profit_rate:+.2f}%) | 持有{hold_days}天")
        
        # 原因行
        lines.append(f"📝 原因: {reason}")
        
        # 分隔线
        lines.append("━" * 50)
        
        return lines

# ============================================================================
# 导出列表
# ============================================================================

__all__ = [
    # 主类
    'SignalFormatter',
    'TradeFormatter',
    
    # 枚举类型
    'SignalType',
    'ConditionType',
    
    # 便捷函数
    'format_signal',
    'format_compact',
    'format_detailed',
    'extract_condition_type',
]

